package com.yuyu.common.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;

public final class DateUtil {

    public static final String PATTERN_DATE = "yyyy-MM-dd";
    public static final String PATTERN_DATE_S = "yyyyMMdd";
    public static final String PATTERN_DATE_SS = "yyMMdd";
    public static final String PATTERN_MONTH = "yyyy-MM";
    public static final String PATTERN_MONTH_M = "yyyyMM";
    public static final String PATTERN_MONTH_S = "yy-MM";
    public static final String PATTERN_MONTH_MS = "yyMM";
    public static final String PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_DATATIME_GRE = "yyyy/MM/dd HH:mm:ss";

    /**
     * Date转LocalDate
     * @param date
     * @return
     */
    public static LocalDate toLocalDate(Date date) {
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        return localDate;
    }

    /**
     * Date转LocalDateTime
     * @param date
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return localDateTime;
    }

    /**
     * 转换指定格式的字符串为时间
     *
     * @param str
     * @param pattern
     * @return
     */
    public static Date formatStr2Date(String str, String pattern) {
        Date d = null;
        if (null != str && !str.trim().equals("")) {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            try {
                d = sdf.parse(str);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        return d;
    }

    /**
     * 转换时间为指定格式的字符串
     *
     * @param date
     * @return
     */
    public static String formatDate2Str(Date date, String pattern) {
        if (null == date) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String s = sdf.format(date);
        return s;
    }

    /**
     * Calendar转换为Date
     *
     * @param calendar
     * @return
     */
    public static Date calendar2Date(Calendar calendar) {
        if (null == calendar) {
            return null;
        }
        return calendar.getTime();
    }

    /**
     * Date转换为Calendar
     *
     * @param date
     * @return
     */
    public static Calendar date2Calendar(Date date) {
        if (null == date) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 获取1天中的小时
     *
     * @param date
     * @return
     */
    public static Integer getHours(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        Integer hour = calendar.get(Calendar.HOUR);
        return hour;
    }


    /**
     * 计算指定日期是该年中的第几周
     *
     * @param date
     * @return
     */
    public static Integer getWeekOfYear(Date date) {
        if (null == date) {
            return 0;
        }
        return date2Calendar(date).get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 计算指定日期是该年中的第几天
     *
     * @param date
     * @return
     */
    public static Integer getDayOfYear(Date date) {
        if (null == date) {
            return 0;
        }
        return date2Calendar(date).get(Calendar.DAY_OF_YEAR);
    }

    /**
     * 计算指定日期是该月中的第几天
     *
     * @param date
     * @return
     */
    public static Integer getDayOfMonth(Date date) {
        if (null == date) {
            return 0;
        }
        return date2Calendar(date).get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 计算指定日期是月中的第几个星期
     *
     * @param date
     * @return
     */
    public static Integer getDayOfWeekInMonth(Date date) {
        if (null == date) {
            return 0;
        }
        return date2Calendar(date).get(Calendar.DAY_OF_WEEK_IN_MONTH);
    }

    /**
     * 计算指定日期是该周中的第几天(星期天1~~~星期六7)
     *
     * @param date
     * @return
     */
    public static Integer getDayOfWeek(Date date) {
        if (null == date) {
            return 0;
        }
        return date2Calendar(date).get(Calendar.DAY_OF_WEEK);
    }

    /**
     * 计算指定日期月份的最大天数
     *
     * @param date
     * @return
     */
    public static int getMaxDayInMonth(Date date) {
        if (date == null) {
            return 0;
        }
        return date2Calendar(date).getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 给指定日期添加或减去指定年
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addYear(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的年份
     *
     * @param date
     * @param year
     * @return
     */
    public static Date setYear(Date date, int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.YEAR, year);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定月
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addMonth(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期月份
     *
     * @param date
     * @param month
     * @return
     */
    public static Date setMonth(Date date, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH, month);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定周
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addWeek(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.WEEK_OF_MONTH, amount);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定天
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addDay(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的天数
     *
     * @param date
     * @param day
     * @return
     */
    public static Date setDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, day);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定小时
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addHour(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date setHour(Date date, int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定分钟
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addMinute(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的分钟
     *
     * @param date
     * @param minute
     * @return
     */
    public static Date setMinute(Date date, int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, minute);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定秒
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addSecond(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的秒
     *
     * @param date
     * @param second
     * @return
     */
    public static Date setSecond(Date date, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, second);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加或减去指定毫秒
     *
     * @param date
     * @param amount
     * @return
     */
    public static Date addMillisecond(Date date, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MILLISECOND, amount);
        return calendar.getTime();
    }

    /**
     * 指定日期的毫秒
     *
     * @param date
     * @param millisecond
     * @return
     */
    public static Date setMillisecond(Date date, int millisecond) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

    /**
     * 计算两个日期之间差的多少毫秒，如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long compareMillisecond(Date firstDate, Date secondDate) {
        long time1 = firstDate.getTime();
        long time2 = secondDate.getTime();
        return (time1 - time2);
    }

    /**
     * 计算两个日期之间差的多少秒，如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long compareSecond(Date firstDate, Date secondDate) {
        long time1 = firstDate.getTime();
        long time2 = secondDate.getTime();
        return ((time1 - time2) / (1000));
    }

    /**
     * 计算两个日期之间差的多少分钟，如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long compareMinute(Date firstDate, Date secondDate) {
        long time1 = firstDate.getTime();
        long time2 = secondDate.getTime();
        return ((time1 - time2) / (1000 * 60));
    }

    /**
     * 计算两个日期之间差的多少小时，如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long compareHour(Date firstDate, Date secondDate) {
        long time1 = firstDate.getTime();
        long time2 = secondDate.getTime();
        return ((time1 - time2) / (1000 * 60 * 60));
    }

    /**
     * 计算两个日期之间差的多少天，如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static long compareDay(Date firstDate, Date secondDate) {
        long time1 = firstDate.getTime();
        long time2 = secondDate.getTime();
        return ((time1 - time2) / (1000 * 60 * 60 * 24));
    }

    /**
     * 计算两个日期之间差的多少天， 如果日期firstDate在日期secondDate的后面则返回一个正数、如果日期firstDate在日期secondDate的前面则返回一个负数、两个日期相同返回0
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static int compareDateForDay(Date firstDate, Date secondDate) throws Exception {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date fDdate = formatter.parse(formatter.format(firstDate));
        Date sDate = formatter.parse(formatter.format(secondDate));
        return fDdate.compareTo(sDate);
    }

    /**
     * 获取指定日期对应的年份的第一天的日期
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_YEAR, 1);// 设为日期为今年的第1天
        return calendar.getTime();
    }

    /**
     * 获取指定日期对应的年份的最后一天的日期
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_YEAR, 1);// 设为日期为今年的第1天
        calendar.add(Calendar.YEAR, 1);// 加上一年，到第二年的第一天
        calendar.add(Calendar.DATE, -1);// 减一天，今年的最后一天
        return calendar.getTime();
    }

    /**
     * 获取指定日期对应的季度的第一天的日期
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfQuarter(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int month = calendar.get(Calendar.MONTH);
        if (0 == month || 1 == month || 2 == month) {
            calendar.set(Calendar.MONDAY, 0);
        } else if (3 == month || 4 == month || 5 == month) {
            calendar.set(Calendar.MONDAY, 3);
        } else if (6 == month || 7 == month || 8 == month) {
            calendar.set(Calendar.MONDAY, 6);
        } else {
            calendar.set(Calendar.MONDAY, 9);
        }
        return getFirstDayOfMonth(calendar.getTime());
    }

    /**
     * 获取指定日期对应的季度的最后一天的日期
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfQuarter(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int month = calendar.get(Calendar.MONTH);
        if (0 == month || 1 == month || 2 == month) {
            calendar.set(Calendar.MONDAY, 2);
        } else if (3 == month || 4 == month || 5 == month) {
            calendar.set(Calendar.MONDAY, 5);
        } else if (6 == month || 7 == month || 8 == month) {
            calendar.set(Calendar.MONDAY, 8);
        } else {
            calendar.set(Calendar.MONDAY, 11);
        }
        return getLastDayOfMonth(calendar.getTime());
    }

    /**
     * 获取指定日期对应的月份的第一天的日期
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);// 设为当前月的1号
        return calendar.getTime();
    }

    /**
     * 获取指定日期对应的月份的最后一天的日期
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);// 设为当前月的1号
        calendar.add(Calendar.MONTH, 1);// 加一个月，变为下月的1号
        calendar.add(Calendar.DATE, -1);// 减去一天，变为当月最后一天
        return calendar.getTime();
    }

    /**
     * 获取指定日期对应的周的第一天的日期(按中国习惯星期一作为一周的第一天)
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfWeek(Date date) {
        int dayOfWeek = getDayOfWeek(date);
        if (2 == dayOfWeek) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        while (true) {
            calendar.add(Calendar.DATE, -1);
            if (2 == getDayOfWeek(calendar.getTime())) {
                break;
            }
        }
        return calendar.getTime();
    }

    /**
     * 获取指定日期对应的周的最后一天的日期(按中国习惯星期天作为一周的最后一天)
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfWeek(Date date) {
        int dayOfWeek = getDayOfWeek(date);
        if (1 == dayOfWeek) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        while (true) {
            calendar.add(Calendar.DATE, 1);
            if (1 == getDayOfWeek(calendar.getTime())) {
                break;
            }
        }
        return calendar.getTime();
    }

    /**
     * 当前日期前N天,后N天
     * DateUtils.getNextDay()<BR>
     *
     * @param date
     * @return
     */
    public static Date getNextDay(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, num);
        date = calendar.getTime();
        return date;
    }

    /**
     * 本地时间转UTC时间
     *
     * @param date
     * @return
     */
    public static Date dateToUTC(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR_OF_DAY, -8);
        return cal.getTime();
    }

    /**
     * 按指定格式将本地时间转UTC时间字符串
     *
     * @param date
     * @param pattern
     * @return
     */
    public static String dateToUTCStr(Date date, String pattern) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.HOUR_OF_DAY, -8);
        Date utcDate = cal.getTime();
        String utcDateStr = formatDate2Str(utcDate, pattern);
        return utcDateStr;
    }
}
